﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace XCoder
{
    /// <summary>
    /// 表信息
    /// </summary>
    public class TableInfo
    {
        /// <summary>
        /// 获取绑定的数据库
        /// </summary>
        public DatabaseInfo Database { get; private set; }

        /// <summary>
        /// 获取表名称
        /// </summary>
        public string TableName { get; private set; }

        /// <summary>
        /// 是否是视图
        /// </summary>
        public bool IsView { get; set; }

        /// <summary>
        /// 获取表备注
        /// </summary>
        public string Comment { get; set; }

        public string GetModelNameSpace()
        {
            return string.Concat(this.Database.ModelNameSpace, ".", this.TableName);
        }

        public string GetDALNameSpace()
        {
            return string.Concat(this.Database.DALNameSpace, ".", this.TableName);
        }

        public string GetBLLNameSpace()
        {
            return string.Concat(this.Database.BLLNameSpace, ".", this.TableName);
        }

        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="tableName"></param>
        /// <param name="tableName"></param>
        public TableInfo(DatabaseInfo dbInfo, string tableName, string comment = null)
        {
            this.Database = dbInfo;
            this.TableName = tableName;
            this.Comment = comment;
        }

        private System.Collections.Generic.List<ColumnInfo> columns;
        /// <summary>
        /// 获取字段映射列表
        /// </summary>
        public System.Collections.Generic.List<ColumnInfo> Columns
        {
            get
            {
                if (this.columns == null)
                    this.columns = new System.Collections.Generic.List<ColumnInfo>();
                return columns;
            }
        }

        /// <summary>
        /// 转换成 Model 代码
        /// </summary>
        /// <returns></returns>
        public string ToModelCode()
        {
            int index = 0;

            StringBuilder modelCode = new StringBuilder();

            #region 添加注释

            modelCode.AppendLine("    /// <summary>");
            foreach (string item in (this.Comment ?? string.Empty).Split(new string[] { Environment.NewLine }, System.StringSplitOptions.RemoveEmptyEntries))
            {
                modelCode.AppendLine(string.Format("    /// {0}", item));
            }
            modelCode.AppendLine("    /// </summary>");

            #endregion

            #region 添加特性

            modelCode.AppendLine("    [System.Serializable]");

            #endregion

            #region 添加类

            modelCode.AppendFormat("    public partial class {0} : System.ICloneable", this.TableName); modelCode.AppendLine();
            //  开始
            modelCode.AppendLine("    {");

            #region 添加属性

            if (this.Columns.Count > 0)
            {
                this.Columns.ForEach(x => { modelCode.AppendLine(x.ToModelCode()); });
            }

            #endregion

            #region 添加克隆方法

            modelCode.AppendLine("        /// <summary>");
            modelCode.AppendLine(string.Format("        /// 克隆 {0} 对象", this.TableName));
            modelCode.AppendLine("        /// </summary>");
            modelCode.AppendLine("        /// <returns></returns>");
            modelCode.AppendLine("        public object Clone()");
            modelCode.AppendLine("        {");
            modelCode.AppendLine(string.Format("            {0} model = new {0}();", this.TableName));
            this.Columns.ForEach(x => { modelCode.AppendLine(string.Format("            model.{0} = this.{0};", x.ColumnName)); });
            modelCode.AppendLine("            return model;");
            modelCode.AppendLine("        }");

            #endregion

            #region 添加Load方法

            if (this.Database.Generate_Model_Load_Method)
            {
                index = 0;
                modelCode.AppendLine();
                modelCode.AppendLine(string.Format("        public static {0} Load(System.Data.IDataReader reader)", this.TableName));
                modelCode.AppendLine("        {");
                modelCode.AppendLine(string.Format("            {0} model = null;", this.TableName));
                modelCode.AppendLine("            if (reader != null && !reader.IsClosed && reader.Read())");
                modelCode.AppendLine("            {");
                modelCode.AppendLine(string.Format("                model = new {0}();", this.TableName));
                modelCode.AppendLine("                for (int i = 0; i < reader.FieldCount; i++)");
                modelCode.AppendLine("                {");
                modelCode.AppendLine("                    string name = reader.GetName(i);");
                this.Columns.ForEach(x =>
                {
                    if (index == 0)
                    {
                        modelCode.AppendLine(string.Format("                    if (string.Equals(name, \"{0}\", System.StringComparison.CurrentCultureIgnoreCase))", x.ColumnName));
                    }
                    else
                    {
                        modelCode.AppendLine(string.Format("                    else if (string.Equals(name, \"{0}\", System.StringComparison.CurrentCultureIgnoreCase))", x.ColumnName));
                    }
                    modelCode.AppendLine(string.Format("                        model.{0} = reader[i] as {1};", x.ColumnName, x.GetCodeType()));
                    index++;
                });
                modelCode.AppendLine("                }");
                modelCode.AppendLine("            }");
                modelCode.AppendLine("            return model;");
                modelCode.AppendLine("        }");
            }

            #endregion

            #region 添加LoadDataRow方法

            if (this.Database.Generate_Model_LoadDataRow_Method)
            {
                modelCode.AppendLine();
                modelCode.AppendLine(string.Format("        public static {0} LoadDataRow(System.Data.DataRow row)", this.TableName));
                modelCode.AppendLine("        {");
                modelCode.AppendLine(string.Format("            {0} model = null;", this.TableName));
                modelCode.AppendLine("            if (row != null)");
                modelCode.AppendLine("            {");
                modelCode.AppendLine(string.Format("                model = new {0}();", this.TableName));
                this.Columns.ForEach(x =>
                {
                    string str = string.Empty;
                    modelCode.AppendLine(string.Format("                if (row.Table.Columns.Contains(\"{0}\"))", x.ColumnName));
                    modelCode.AppendLine(string.Format("                    model.{0} = row[\"{0}\"] as {1};", x.ColumnName, x.GetCodeType()));
                });
                modelCode.AppendLine("            }");
                modelCode.AppendLine("            return model;");
                modelCode.AppendLine("        }");

            }

            #endregion

            #region 添加 Compare方法

            if (this.Database.Generate_Model_Compare_Method)
            {
                modelCode.AppendLine();
                modelCode.AppendLine("        /// <summary>");
                modelCode.AppendLine(string.Format("        /// 比较 {0} 对象", this.TableName));
                modelCode.AppendLine("        /// </summary>");
                modelCode.AppendLine(string.Format("        /// <param name=\"newModel\"> 新的 {0} 对象实例 </param>", this.TableName));
                modelCode.AppendLine("        /// <returns> 返回哈希列表 </returns>");
                modelCode.AppendLine(string.Format("        public System.Collections.Hashtable Compare({0} newModel)", this.TableName));
                modelCode.AppendLine("        {");
                modelCode.AppendLine("            System.Collections.Hashtable lst = new System.Collections.Hashtable();");
                modelCode.AppendLine("            if (newModel != null && newModel != this)");
                modelCode.AppendLine("            {");
                this.Columns.ForEach(x =>
                {
                    modelCode.AppendLine(string.Format("                if (newModel.{0} != this.{0})", x.ColumnName));
                    modelCode.AppendLine(string.Format("                    lst.Add(\"{0}\", newModel.{0});", x.ColumnName));
                });
                modelCode.AppendLine("            }");
                modelCode.AppendLine("            return lst;");
                modelCode.AppendLine("        }");

            }

            #endregion

            //  结束
            modelCode.AppendLine("    }");

            #endregion

            return modelCode.ToString();
        }

        /// <summary>
        /// 转换成 DAL 代码
        /// </summary>
        /// <returns></returns>
        public string ToDalCode()
        {
            StringBuilder dalCode = new StringBuilder();

            #region 添加注释

            dalCode.AppendLine("    /// <summary>");
            dalCode.AppendLine(string.Format("    /// {0}", this.Comment));
            dalCode.AppendLine("    /// </summary>");
            dalCode.AppendLine(string.Format("    public partial class {0}", this.TableName));
            dalCode.AppendLine("    {");

            #endregion

            List<ColumnInfo> pkColumns = this.Columns.FindAll(x => x.IsPrimaryKey);

            //  定义主键参数列表
            StringBuilder pKArray = new StringBuilder();
            int index = 0;
            pkColumns.ForEach(x =>
            {
                if (index > 0)
                    pKArray.Append(",");
                pKArray.AppendFormat("{0} {1}", x.DataType, x.ColumnName);
                index++;
            });

            #region 添加
            {
                if (!this.IsView)
                {

                    dalCode.AppendLine("        /// <summary>");
                    dalCode.AppendLine("        /// 添加");
                    dalCode.AppendLine("        /// </summary>");
                    dalCode.AppendLine(string.Format("        /// <param name=\"model\">{0}</param>", this.Comment));
                    dalCode.AppendLine(string.Format("        public bool Add({0})", string.Concat(this.GetModelNameSpace(), " ", "model")));
                    dalCode.AppendLine("        {");

                    StringBuilder strSql1 = new StringBuilder();
                    StringBuilder strSql2 = new StringBuilder();
                    StringBuilder valuesStr = new StringBuilder();
                    index = 0;
                    this.Columns.ForEach(x =>
                    {
                        //  非自动增长列
                        if (!x.AutoIncrement)
                        {
                            if (index > 0)
                            {
                                strSql1.Append(",");
                                strSql2.Append(",");
                                valuesStr.Append(",");
                            }
                            strSql1.Append(x.ColumnName);
                            strSql2.Append(string.Concat("{", index.ToString(), "}"));
                            valuesStr.AppendLine(string.Format("                model.{0}", x.ColumnName));
                            index++;
                        }
                    });

                    string sql = string.Concat("insert into ", this.TableName, "(", strSql1.ToString(), ") values(", strSql2.ToString(), ")");

                    dalCode.AppendLine(string.Concat("            string strSql = @\"", sql, "\" ;"));
                    dalCode.AppendLine(string.Format("            int n = {0}.ExecuteNonQueryFormat(", this.Database.DbHelperObjectName));
                    dalCode.AppendLine("                strSql");
                    if (valuesStr.Length > 0)
                        dalCode.Append(",");
                    dalCode.Append(valuesStr.ToString());
                    dalCode.AppendLine("                );");

                    dalCode.AppendLine("            return n > 0;");
                    dalCode.AppendLine("        }");
                    dalCode.AppendLine();

                }
            }
            #endregion

            #region 修改
            {
                dalCode.AppendLine("        /// <summary>");
                dalCode.AppendLine("        /// 更新");
                dalCode.AppendLine("        /// </summary>");
                dalCode.AppendLine("        /// <param name=\"oldModel\"> 旧的实体 </param>");
                dalCode.AppendLine("        /// <param name=\"newModel\"> 新的实体 </param>");
                dalCode.AppendLine(string.Format("        public bool Update({0})", string.Concat(this.GetModelNameSpace(), " oldModel", ", ", this.GetModelNameSpace(), " newModel")));
                dalCode.AppendLine("        {");
                dalCode.AppendLine("            var lst = oldModel.Compare(newModel);");
                dalCode.AppendLine("            if (lst.Count == 0) { return true; }");
                dalCode.AppendLine("            else");
                dalCode.AppendLine("            {");
                dalCode.AppendLine("                int index = 0; var strSetSql = new System.Text.StringBuilder(); var values = new System.Collections.Generic.List<object>();");
                dalCode.AppendLine("                foreach (System.Collections.DictionaryEntry item in lst)");
                dalCode.AppendLine("                {");
                dalCode.AppendLine("                    if (index > 0) { strSetSql.Append(\", \"); }");
                dalCode.AppendLine("                    strSetSql.Append(string.Concat(item.Key, \"={\", index.ToString(), \"}\")); values.Add(item.Value); index++;");
                dalCode.AppendLine("                }");

                StringBuilder strWhere = new StringBuilder();

                index = 0;
                this.Columns.ForEach(x =>
                {
                    //  主键列
                    if (x.IsPrimaryKey)
                    {
                        if (index > 0)
                        {
                            strWhere.Append(" and ");
                        }
                        strWhere.Append(string.Concat(x.ColumnName, "=", "{", index.ToString(), "}"));
                        index++;
                    }
                });

                dalCode.AppendLine(string.Concat("                string strSql = string.Concat(\"update ", this.TableName, " set \", strSetSql.ToString(), \" where ", strWhere.ToString(), "\");"));
                dalCode.AppendLine(string.Format("                return {0}.ExecuteNonQueryFormat(strSql, values) > 0;", this.Database.DbHelperObjectName));
                dalCode.AppendLine("            }");
                dalCode.AppendLine("        }");
            }
            #endregion

            #region 删除
            {
                dalCode.AppendLine("        /// <summary>");
                dalCode.AppendLine("        /// 删除");
                dalCode.AppendLine("        /// </summary>");
                pkColumns.ForEach(x =>
                {
                    dalCode.AppendLine(string.Format("        /// <param name=\"{0}\">{1}</param>", x.ColumnName, x.Comment));
                });
                dalCode.AppendLine(string.Format("        public bool Delete({0})", pKArray));
                dalCode.AppendLine("        {");

                StringBuilder strWhere = new StringBuilder();
                StringBuilder valuesStr = new StringBuilder();
                index = 0;
                this.Columns.ForEach(x =>
                {
                    //  主键列
                    if (x.IsPrimaryKey)
                    {
                        if (index > 0)
                        {
                            strWhere.Append(" and ");
                            valuesStr.Append(",");
                        }
                        strWhere.Append(string.Concat(x.ColumnName, "=", "{", index.ToString(), "}"));
                        valuesStr.AppendLine(string.Format("                {0}", x.ColumnName));
                        index++;
                    }
                });

                string sql = string.Concat("delete from ", this.TableName, " where ", strWhere.ToString());

                dalCode.AppendLine(string.Concat("            string strSql = @\"", sql, "\" ;"));
                dalCode.AppendLine(string.Format("            int n = {0}.ExecuteNonQueryFormat(", this.Database.DbHelperObjectName));
                dalCode.AppendLine("                strSql");
                if (valuesStr.Length > 0)
                    dalCode.Append(",");
                dalCode.Append(valuesStr.ToString());
                dalCode.AppendLine("                );");
                dalCode.AppendLine("            return n > 0;");
                dalCode.AppendLine("        }");
                dalCode.AppendLine();
            }
            #endregion

            #region 查询

            #region GetModel
            {
                dalCode.AppendLine("        /// <summary>");
                dalCode.AppendLine("        /// GetModel");
                dalCode.AppendLine("        /// </summary>");
                pkColumns.ForEach(x =>
                {
                    dalCode.AppendLine(string.Format("        /// <param name=\"{0}\">{1}</param>", x.ColumnName, x.Comment));
                });
                dalCode.AppendLine(string.Format("        public {0} GetModel({1})", this.GetModelNameSpace(), pKArray));
                dalCode.AppendLine("        {");

                StringBuilder strWhere = new StringBuilder();
                StringBuilder valuesStr = new StringBuilder();
                index = 0;
                this.Columns.ForEach(x =>
                {
                    //  主键列
                    if (x.IsPrimaryKey)
                    {
                        if (index > 0)
                        {
                            strWhere.Append(" and ");
                            valuesStr.Append(",");
                        }
                        strWhere.Append(string.Concat(x.ColumnName, "=", "{", index.ToString(), "}"));
                        valuesStr.Append(string.Format("{0}", x.ColumnName));
                        index++;
                    }
                });

                string sql = string.Concat("select * from ", this.TableName, " where ", strWhere.ToString());

                dalCode.AppendLine(string.Concat("            string strSql = @\"", sql, "\" ;"));
                dalCode.Append(string.Format("            using (var reader = {0}.ExecuteReaderFormat(strSql", this.Database.DbHelperObjectName));
                if (valuesStr.Length > 0)
                    dalCode.Append(",");
                dalCode.Append(valuesStr.ToString());
                dalCode.Append("))");
                dalCode.AppendLine();
                dalCode.AppendLine("            {");
                dalCode.AppendLine(string.Format("                return {0}.Load(reader);", this.GetModelNameSpace()));
                dalCode.AppendLine("            }");
                dalCode.AppendLine("            return null;");
                dalCode.AppendLine("        }");
                dalCode.AppendLine();
            }
            #endregion

            #endregion

            dalCode.AppendLine("    }");
            return dalCode.ToString();
        }

        /// <summary>
        /// 转换成 BLL 代码
        /// </summary>
        /// <returns></returns>
        public string ToBllCode()
        {
            StringBuilder bllCode = new StringBuilder();
            return bllCode.ToString();
        }
    }
}
